package com.dxy.netty.tcppackagesolve;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

/**
 * @Description "头部包含数据包长度"方式解决粘包拆包问题-netty服务端
 * <p>
 * 参考1：netty中tcp粘包拆包问题及解决方法
 * https://blog.csdn.net/PacosonSWJTU/article/details/126798838
 * <p>
 * 参考2：netty 数据包黏包拆包处理器使用及遇到的问题
 * https://blog.csdn.net/u011035407/article/details/80454511
 * <p>
 * 参考2：20-Netty TCP 粘包和拆包及解决方案
 * https://blog.51cto.com/u_15196075/5055760
 * @Author dangxianyue
 * @Date 2023/1/8 21:48
 */
public class ProtocolNettyServer {

    private final int port;

    public ProtocolNettyServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) {
        try {
            new ProtocolNettyServer(8089).run();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void run() throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(8);
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ProtocolNettyServerInitializer()); // 自定义一个初始化类
            // 自动服务器
            ChannelFuture channelFuture = serverBootstrap.bind(this.port).sync();
            System.out.println("服务器启动成功");
            // 监听关闭
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    static class ProtocolNettyServerInitializer extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            //pipeline.addLast(new LoggingHandler(LogLevel.INFO));

            //这里使用自定义分隔符
            ByteBuf delimiter = Unpooled.copiedBuffer("\r\n".getBytes());
            pipeline.addFirst(new DelimiterBasedFrameDecoder(8192, delimiter));

            // 添加入站解码器-把字节转为协议报文便于业务逻辑处理
            pipeline.addLast(new ProtocolMessageDecoder());
            // 添加出站编码器-把协议报文转为字节便于网络传输
            pipeline.addLast(new ProtocolMessageEncoder());

            // 添加业务逻辑handler
            pipeline.addLast(new ProtocolNettyServerHandler());
        }
    }
}
